package FieldHash;
use strict;
use warnings;
use SimpleError;

use constant DATA_KEY  => 'Data';
use constant NAME_KEY  => 'Name';
use constant TABLE_KEY => 'Table';

## normal member methods

sub new {
    my $class = shift;
    my ($self, $name, $data);
    $name = shift if (@_ > 0 && ref($_[0]) eq 'ARRAY');
    $data = shift if (@_ > 0 && ref($_[0]) eq 'ARRAY');
    $self = +{ NAME_KEY() => $name, DATA_KEY() => $data,  @_ };
    bless $self, $class;
    if (defined( $self->{NAME_KEY()} )) {
        $self->make_table();
    }
    return $self;
}

sub data {
    my $self = shift;
    my ($new_data) = @_;
    if (defined($new_data)) {
        $self->{DATA_KEY()} = $new_data;
    }
    return $self->{DATA_KEY()};
}

sub name {
    my $self = shift;
    my ($new_name) = @_;
    if (defined($new_name)) {
        $self->{NAME_KEY()} = $new_name;
        $self->make_table();
    }
    return $self->{NAME_KEY()};
}

sub index_of_key {
    my $self = shift;
    my ($key) = @_;
    my $index = $self->{TABLE_KEY()}{$key};
    error("$key: no such key") unless defined($index);
    return $index;
}

## private methods

sub make_table {
    my $self = shift;
    my $name = $self->{NAME_KEY()};
    error("error: names not set") unless (defined($name) && @$name > 0);
    my %table;
    for my $i (0 .. $#$name) {
        $table{ $name->[$i] } = $i; # reverse indexing: VDD18C_display ==> array[22]
    }
    $self->{TABLE_KEY()} = \%table;
}

## tied methods

sub TIEHASH {
    return &new(@_);
}

sub FETCH {
    my $self = shift;
    my ($key) = @_;
    my $index = $self->{TABLE_KEY()}{$key};
    error("Invalid key: $key") unless defined($index);
    return $self->{DATA_KEY()}[ $index ];
}

sub STORE {
    my $self = shift;
    my ($key, $value) = @_;
    my $index = $self->{TABLE_KEY()}{$key};
    error("Invalid key: $key") unless defined($index);
    $self->{DATA_KEY()}[ $index ] = $value;
    return $self->{DATA_KEY()}[ $index ];
}

sub EXISTS {
    my $self = shift;
    my ($key) = @_;
    return exists( $self->{TABLE_KEY()}{$key} );
}

sub FIRSTKEY {
    my $self = shift;
    return scalar each( %{ $self->{TABLE_KEY()} } );
}

sub NEXTKEY {
    my $self = shift;
    return scalar each( %{ $self->{TABLE_KEY()} } );
}

1;
